﻿using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core.Caching;
using Nop.Core.Data;
using Nop.Core;
using System.Net;
using System.IO;
using System.Collections;
using Nop.Core.Infrastructure;
using Nop.Services.Configuration;
using System.Text.RegularExpressions;
using System.Threading;
using Nop.Plugin.Widgets.EKomi.Models;
using Nop.Services.Stores;
using System.Web;
using Nop.Core.Domain.Customers;
using Nop.Services.Common;

namespace Nop.Plugin.Widgets.EKomi.Services
{
    public partial class EKomiService : IEKomiService
    {
        #region Fields

        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IStoreService _storeService;
        private readonly HttpContextBase _httpContext;
        private readonly IWebHelper _webHelper;
        private readonly ISettingService _settingService;
        private readonly ICacheManager _cacheManager;
        private readonly Regex _regex;

        #endregion

        #region Ctor

        public EKomiService(IWorkContext workContext,
           IStoreContext storeContext, IStoreService storeService,
            HttpContextBase httpContext,
            IWebHelper webHelper,
            ISettingService settingService,
            ICacheManager cacheManager)
        {
            this._workContext = workContext;
            this._storeContext = storeContext;
            this._storeService = storeService;
            this._httpContext = httpContext;
            this._webHelper = webHelper;
            this._settingService = settingService;
            this._cacheManager = EngineContext.Current.ContainerManager.Resolve<ICacheManager>("nop_cache_static");
            System.Text.RegularExpressions.RegexOptions options = ((System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace | System.Text.RegularExpressions.RegexOptions.Multiline)
                | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            _regex = new Regex("(?:^|,)(\\\"(?:[^\\\"]+|\\\"\\\")*\\\"|[^,]*)", options);
        }

        #endregion

        public virtual int GetActiveStoreScopeConfiguration(IStoreService storeService, IWorkContext workContext)
        {
            //ensure that we have 2 (or more) stores
            if (storeService.GetAllStores().Count < 2)
                return 0;

            var storeId = workContext.CurrentCustomer.GetAttribute<int>(SystemCustomerAttributeNames.AdminAreaStoreScopeConfiguration);
            var store = storeService.GetStoreById(storeId);
            return store != null ? store.Id : 0;
        }

        #region Methods
        protected virtual string[] SplitCSV(string line)
        {
            MatchCollection coll = _regex.Matches(line);
            string[] items = new string[coll.Count];
            int i = 0;
            foreach (Match m in coll)
            {
                items[i++] = m.Groups[0].Value.Trim('"').Trim(',').Trim('"').Trim();
            }
            return items;
        }

        private delegate IList<Feedback> GetAllHandler(bool clearCache = false);
        public IList<Feedback> GetAll(bool clearCache = false)
        {
            //load settings for a chosen store scope
            var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
            var spreadButtonSettings = _settingService.LoadSetting<EKomiSettings>(storeScope);

            string key = Nop.Plugin.Widgets.EKomi.Controllers.EKomiController.FEEDBACK_ALL_KEY;
            if (clearCache) _cacheManager.Remove(key);
            var allfeeds = _cacheManager.Get(key, 3600, () =>
            {
                List<Feedback> feeds = new List<Feedback>();
                string url = string.Format("http://api.ekomi.de/get_feedback.php?interface_id={0}&interface_pw={1}&type=csv&product=tout", spreadButtonSettings.InterfaceId, spreadButtonSettings.InterfacePassword);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    String ver = response.ProtocolVersion.ToString();
                    StreamReader reader = new StreamReader(response.GetResponseStream());

                    while (reader.Peek() >= 0)
                    {
                        try
                        {
                            string line = reader.ReadLine();
                            string[] values = SplitCSV(line);
                            int orderId;
                            int.TryParse(values[1], out orderId);
                            byte rating;
                            if (!byte.TryParse(values[2], out rating)) rating = 5;
                            string comment = values[3];
                            feeds.Add(new Feedback() { Rating = rating, Comment = comment, OrderId = orderId });
                        }
                        catch (Exception)
                        {
                        }
                    }

                }

                return feeds.ToArray();
            });
            return allfeeds;
        }

        public virtual IList<Feedback> GetRandom(int nb, byte ratingMini, byte lenghtMini)
        {
            try
            {
                string key = Nop.Plugin.Widgets.EKomi.Controllers.EKomiController.FEEDBACK_ALL_KEY;

                //If not already in the cache we call GetAll asynchronously and return a temporary result
                if (!_cacheManager.IsSet(key))
                {
                    var h = new GetAllHandler(GetAll);
                    h.BeginInvoke(true, null, null);
                    return new Feedback[] { new Feedback() { Comment = "Feedback is not already loaded, but this site is amazing!", Rating = 5 } };
                }

                //It is in the cache, we get it
                var allfeeds = _cacheManager.Get(key, 1, () =>
                {
                    //Shoult never be used, that is the reason why cachetime is 1
                    return new Feedback[] { new Feedback() { Comment = "", Rating = 5 } };
                });


                //Put in cache a filtered selection so each query will just have to pick up random feed in this array
                var widgetfeeds = _cacheManager.Get(Nop.Plugin.Widgets.EKomi.Controllers.EKomiController.FEEDBACK_FILTER_KEY, 300, () =>
                {
                    return allfeeds.Where(x => x.Rating >= ratingMini && x.Comment.Length >= lenghtMini).ToArray();
                });

                if (widgetfeeds.Length == 0) //To avoid error on random.next function
                    return new Feedback[] { new Feedback() { Comment = "", Rating = 5 } };

                //pick up random feed in the filterd array
                Random random = new Random();
                int indexMax = widgetfeeds.Length - 1;
                List<Feedback> rndfeeds = new List<Feedback>();
                for (int i = 0; i < nb; i++)
                {
                    int index = random.Next(0, indexMax);
                    var feed = widgetfeeds[index];
                    rndfeeds.Add(feed);
                }

                return rndfeeds;

            }
            catch (Exception)
            {
                return new Feedback[] { new Feedback() { Comment = "", Rating = 5 } };
            }

        }


        #endregion

    }

}
